package ducpham.rogueconsole.mark1;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.lang.reflect.Field;
import java.util.Observer;

import javax.swing.JComponent;

/**
 * Class implementing a JComponent, Which display a dynamic character console.
 * The console would be useful for creating games based on ASCII graphics The
 * name is derived from roguelike games.
 * 
 * @author minhduc
 * 
 * @version: 0.01
 * @since: Apr 25t 2011
 * 
 * 
 */

public class RConsole extends JComponent {

	// generated serial id
	private static final long serialVersionUID = 8654226442439275259L;

	// set the default tile properties here
	private static final Color DEFAULT_BACKGROUND = Color.BLACK;
	private static final Color BACKGROUND_ALT = Color.DARK_GRAY;
	private static final Font FONT = new Font(Font.MONOSPACED, Font.BOLD, 16);

	private int tileWidth;
	private int tileHeight;
	private int rows;
	private int columns;

	private Color[][] background;
	private Image backgroundImage;
	private Image[][] item;
	private Image itemImage;

	private CharacterSpriteCanvas canvas;

	/**
	 * @param the
	 *            initial columns and rows the console have.
	 */
	public RConsole(int columns, int rows) {

		// get the total size of the console
		this.rows = rows;
		this.columns = columns;
		canvas = new CharacterSpriteCanvas(FONT);

		// get the tile width and height from the canvas
		tileWidth = canvas.getWidth();
		tileHeight = canvas.getHeight();

		// create arrays which cover a tile's properties
		background = new Color[columns][rows];
		item = new Image[columns][rows];

		// fill all tiles with default value
		for (int x = 0; x < columns; x++) {
			for (int y = 0; y < rows; y++) {
				background[x][y] = DEFAULT_BACKGROUND;
			}
		}

		backgroundImage = new BufferedImage(columns * tileWidth, rows
				* tileHeight, BufferedImage.TYPE_4BYTE_ABGR);
		itemImage = new BufferedImage(columns * tileWidth, rows
				* tileHeight, BufferedImage.TYPE_4BYTE_ABGR);

		repaintBackground();

		// set the preferred size according to tile size
		// and tile count
		setPreferredSize(new Dimension(columns * tileWidth, rows * tileHeight));

		// adding mouse adapters
		addMouseListener(new RMouseAdapter(this));
		addMouseMotionListener(new RMouseMotionAdapter(this));

		// turn on double buffering
		setDoubleBuffered(true);
	}

	@Override
	public void paint(Graphics graphics) {
		super.paint(graphics);

		// cast to graphics2d for more functions
		Graphics2D g = (Graphics2D) graphics;

		g.drawImage(backgroundImage, 0, 0, null);
		g.drawImage(itemImage, 0, 0, null);

	}

	@Override
	public void repaint() {
		// TODO Auto-generated method stub
		super.repaint();
		repaintBackground();
		repaintItem();
	}

	private void repaintBackground() {
		Graphics2D g = (Graphics2D) backgroundImage.getGraphics();

		// paint the background
		for (int x = 0; x < columns; x++) {
			for (int y = 0; y < rows; y++) {
				if (background[x][y] == null)
					continue;
				g.setColor(background[x][y]);
				g.fillRect(x * tileWidth, y * tileHeight, tileWidth, tileHeight);
				background[x][y] = null;
			}
		}
	}

	private void repaintItem() {
		Graphics2D g = (Graphics2D) itemImage.getGraphics();
		// paint the items
		for (int x = 0; x < columns; x++) {
			for (int y = 0; y < rows; y++) {
				if (item[x][y] == null)
					continue;
				g.setColor(new Color(0, 0, 0, 1));
				g.clearRect(x * tileWidth, y * tileHeight, tileWidth, tileHeight);
				g.drawImage(item[x][y], x * tileWidth, y * tileHeight, null);
				item[x][y] = null;
			}
		}
	}

	private void announceMouseEvent(MouseEvent e) {

		String eventName = null;
		for (Field field : MouseEvent.class.getFields()) {
			try {
				if (field.getInt(MouseEvent.class) == e.getID())
					eventName = field.getName();
			} catch (Exception e1) {
			}
		}

		String toScreen = "nothing to display";

		int x = e.getX() / tileWidth;
		int y = e.getY() / tileHeight;

		if (eventName != null)
			toScreen = eventName + " " + x + ":" + y + "ế vợ nha";

		clearItemByRect(0, 0, 999, 0);

		char[] sarray = toScreen.toCharArray();
		for (int i = 0; i < sarray.length; i++) {
			item[i][0] = canvas.getCharImage(sarray[i]);
		}

		repaint();

	}

	public void setRows(int rows) {
		this.rows = rows;
	}

	public int getRows() {
		return rows;
	}

	public void setColumns(int columns) {
		this.columns = columns;
	}

	public int getColumns() {
		return columns;
	}

	public void clearItemByRect(int startX, int startY, int endX, int endY) {
		if (startX >= columns || startY >= rows)
			return;
		if (endX >= columns)
			endX = columns - 1;
		if (endY >= rows)
			endY = rows - 1;
		for (int x = startX; x < endX + 1; x++) {
			for (int y = startY; y < endY + 1; y++) {
				item[x][y] = canvas.getCharImage(' ');
			}
		}
	}

	private void setTile(int x, int y, Character ch, Color c) {
		if (x >= columns || y >= rows)
			return;
		if (c != null)
			background[x][y] = c;
		if (ch != null)
			item[x][y] = canvas.getCharImage(ch.charValue());
	}

	public void setTile(int x, int y, char ch, Color c) {
		setTile(x, y, new Character(ch), c);
	}

	public void setTile(int x, int y, char ch) {
		setTile(x, y, new Character(ch), null);
	}

	public void setTile(int x, int y, Color c) {
		setTile(x, y, null, c);
	}

	public void shuffle() {
		// fill all tiles with default value
		for (int x = 0; x < columns; x++) {
			for (int y = 0; y < rows; y++) {
				background[x][y] = DEFAULT_BACKGROUND;
				if (Math.random() * 5 > 4)
					background[x][y] = BACKGROUND_ALT;
				if (Math.random() * 7 > 6)
					background[x][y] = Color.LIGHT_GRAY;
			}
		}
		repaint();
	}

	class RMouseAdapter extends MouseAdapter {

		private RConsole console;

		public RMouseAdapter(RConsole console) {
			this.console = console;
		}

		@Override
		public void mousePressed(MouseEvent e) {
			super.mousePressed(e);
			console.announceMouseEvent(e);
		}
	}

	class RMouseMotionAdapter extends MouseMotionAdapter {

		private RConsole console;

		public RMouseMotionAdapter(RConsole console) {
			this.console = console;
		}

		@Override
		public void mouseMoved(MouseEvent e) {
			// TODO Auto-generated method stub
			super.mouseMoved(e);
			console.announceMouseEvent(e);
		}
	}
}
